/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javamail.sip;

import java.util.List;
import java.util.ListIterator;
import java.util.StringTokenizer;
import javamail.sip.util.eSipHeader;
import javamail.sip.util.eSipMethodType;
import javamail.sip.util.eSipParseState;
import javamail.sip.util.eSipRespCode;

/**
 *
 * @author sriram
 */
public class sipParser {
private static final boolean debugEnabled = false;
String sipText = "INVITE sip:5120@192.168.36.180 SIP/2.0\r\n" +
                    "Via: SIP/2.0/UDP 192.168.6.21:5060\r\n" +
                    "From: sip:5121@192.168.6.21\r\n" +
                    "To: <sip:5120@192.168.36.180>\r\n" +
                    "Call-ID: c2943000-e0563-2a1ce-2e323931@192.168.6.21\r\n" +
                    "CSeq: 100 INVITE\r\n" +
                    "Max-Forwards: 70\r\n" +
                    "User-Agent: Cisco IP Phone/ Rev. 1/ SIP enabled\r\n" +
                    "Accept: application/sdp\r\n" +
                    "Contact: sip:5121@192.168.6.21:5060\r\n" +
                    "Content-Type: application/sdp\r\n";

private String sipVer = "SIP/2.0";
public eSipParseState state = eSipParseState.START;
private sipMessage message = null;

    public sipParser() {
        message = new sipMessage();
    }
    
    public sipParser(List<String> msg) {
        ListIterator list = msg.listIterator();
        sipText = "";
        while (list.hasNext()) {
            sipText += list.next().toString() + "\r\n";
        }
        message = new sipMessage();
    }

    public boolean checkMessage(sipMessage msg) {
        int cidIndex = eSipHeader.CALLID.toInt();
        int fromIndex = eSipHeader.FROM.toInt(); 
        int toIndex = eSipHeader.TO.toInt();
        int contactIndex = eSipHeader.CONTACT.toInt();
        int contentIndex = eSipHeader.CONTENT_LENGTH.toInt();

        if((msg.headers[cidIndex] != null) &&
                (msg.headers[fromIndex] != null) &&
                (msg.headers[toIndex] != null)) {
            try {
                int length = Integer.parseInt(msg.headers[contentIndex]);
                //if(length==0) {
                    state = eSipParseState.COMPLETE;
                //}
            } catch(NumberFormatException e) {
                // Content length is not a NUMBER!! Somethings wrong
                //state = eSipParseState.ERROR;
                if(debugEnabled) 
                    System.out.println("sipParser::checkMessage-Content-Length not a number!"+msg.headers[contentIndex]);
                state = eSipParseState.COMPLETE;
            }
            if(debugEnabled)
                System.out.println("sipParser::checkMessage-Message valid!");
            return true;
        }
        if(debugEnabled)
            System.out.println("sipParser::checkMessage-Invalid Message received!");

        return false;
    }

    public boolean parse() {
        String[] line = sipText.split("\r\n");
        state = eSipParseState.START;
        for(int i=0; i< line.length; i++) {
            parseLine(line[i]);
        }
        return checkMessage(message);
    }
    
    public void parseLine(String line) {
        switch(state) {
            case START:
                parseStartLine(line);
                switch(state) {
                    case REQUEST:
                        message.isRequest = true;
                        parseRequestLine(line);
                        break;
                    case STATUS:
                        message.isRequest = false;
                        parseStatusLine(line);
                        break;
                    default:
                        break;
                }
                break;
            case HEADER:
                parseHeader(line);
                break;
            case BODY:
                parseMessageBody(line);
                break;
            case ERROR:
                break;
            case COMPLETE:
            default:
                break;
        }
    }
    
    public void parseStartLine(String line) {
        if(debugEnabled)
            System.out.println("sipParser::parseStartLine-"+line);
        StringTokenizer tokenizer = new StringTokenizer(line);
        // By default assume that it is a request 
        state = eSipParseState.REQUEST;
        if(tokenizer.hasMoreTokens()) {
            if(tokenizer.nextToken().equals(sipVer)) {
                state = eSipParseState.STATUS;
            }
        } else {
            if(debugEnabled)
                System.out.println("sipParser::parseStartLine-Error: No start line");
            state = eSipParseState.ERROR;
        }
    }
    
    public void parseRequestLine(String line) {
        if(debugEnabled)
            System.out.println("sipParser::parseRequestLine-"+line);

        if(!message.isRequest)
            return;
        
        StringTokenizer tokenizer = new StringTokenizer(line);
        if(tokenizer.hasMoreTokens()) {
            message.method = eSipMethodType.fromString(tokenizer.nextToken());
        }
        // Change state to header
        state = eSipParseState.HEADER;
    }
    
    public void parseStatusLine(String line) {
        if(debugEnabled)
            System.out.println("sipParser::parseStatusLine-"+line);
        
        if(message.isRequest)
            return;
        
        StringTokenizer tokenizer = new StringTokenizer(line);
        if(tokenizer.hasMoreTokens()) {
            String version = tokenizer.nextToken();
            if(tokenizer.hasMoreTokens()) {
                String code = tokenizer.nextToken();
                message.status = eSipRespCode.fromCode(code);
                if(message.status == eSipRespCode.NIL)
                    state = eSipParseState.ERROR;
                else
                    state = eSipParseState.HEADER;
            }
        }
    }
    
    public void parseHeader(String line) {
        if(debugEnabled)
            System.out.println("sipParser::parseHeader-"+line);

        StringTokenizer tokenizer = new StringTokenizer(line);
        if(tokenizer.hasMoreTokens()) {
            String header = tokenizer.nextToken();
            int index = eSipHeader.fromString(header).toInt();
            if(index != 0) {
                // The following code needs to be applied for the VIA header
                // as there can be more than on VIA header.
                if(index == eSipHeader.VIA.toInt() &&
                     (message.headers[index] != null &&
                      !message.headers[index].trim().equals(""))) {
                    message.headers[index] += "\r\n" + eSipHeader.fromInt(index).toString() + 
                            ": " + line.substring(header.length()+1);
                } else
                    message.headers[index] = line.substring(header.length()+1);
            }
            else {
                if(debugEnabled)
                    System.out.println("sipParser::parseHeader-Ignoring header as " +
                            "not look like standard RFC3261 SIP message");
            }
        } else {
            state = eSipParseState.BODY;
        }
            
    }
    
    public void parseMessageBody(String line) {
        if(line !=null && !line.trim().equals("")) {
            if(debugEnabled)
                System.out.println("sipParser::parseMessageBody-"+line);
            message.body.add(line);
        }
        else {
            if(debugEnabled)
                System.out.println("sipParser::parseMessageBody-Parsing Body complete!");
            state = eSipParseState.COMPLETE;
        }
    }

    public sipMessage getMessage() {
        if(state == eSipParseState.COMPLETE) {
            if(debugEnabled)
                System.out.println("sipParser::getMessage-Getting the parsed SIP message");
        return message;
        }
        if(debugEnabled)
            System.out.println("sipParser::getMessage-Parsing not complete, returning null");
        return null;
    }
}
